/*
 *   Copyright (C) 2009 Ultratronik Entwicklungs GmbH 
 *
 *     - Author: Sören Wellhöfer <soeren.wellhoefer@gmx.net>
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 */

#include "aux.hpp"

#include <cstdio>
#include <cstdlib>
#include <cstring>

#include <pty.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>


const std::string Player::exec_name = "maiplayer";

const std::string Player::cmd_codecs[] = {
	"mp4",
	"mpv4",
	"mpv"
};

void Player::tell(std::string cmd) {

	int len, wr, w;
	char buf[128];
		
	wr = w = 0;
	len = cmd.length();
		
	strncpy(buf, cmd.c_str(), len);
	buf[cmd.length()] = '\n';

	// Recover from previous tell
	usleep(500 * 1000);
	
	do {
		w = write(fd_cmd, buf + wr, len - wr + 1);
		if(w == -1) {
			perror("player command failed");
			exit(1);
		}
			
		wr += w;

	} while(wr < len);
}

void Player::launch(int dispw, int disph)
{
	int fd_sla;
	int fd[2];
	
	if(openpty(&fd_cmd, &fd_sla, NULL, NULL, NULL) == -1 ||
	   grantpt(fd_cmd) == -1 ||
	   unlockpt(fd_cmd) == -1) {
		perror("could not setup player environment");
		exit(1);
	}

	if(pipe(fd) == -1) {
		perror("could not setup channel");
		exit(1);
	}
	
	if(!fork()) {

		close(fd_cmd);
		close(fd[0]);

		setvbuf(stdout, NULL, _IONBF, 0);
		
		if(dup2(fd_sla, STDIN_FILENO) == -1||
		   dup2(fd[1], STDOUT_FILENO) == -1) {	

			perror("cannot open channel");
		}
		
		if(execl(("./" + exec_name).c_str(),
			 exec_name.c_str(), "-ue", "-g1", NULL) == -1) {
				
			perror("executing ./maiplayer failed");
			exit(1);
		}
	}

	close(fd_sla);
	close(fd[1]);
	
	int fl = fcntl(fd[0], F_GETFL, 0);
	(void)fcntl(fd[0], F_SETFL, fl | O_NONBLOCK);
	
	if(!(resp = fdopen(fd[0], "r"))) {
		perror("setting up feedback channel");
		exit(1);
	}
	
	tell("setvideodisplay 0,0," + to_string<int>(dispw) + "," +
	     to_string<int>(disph));;
}

/*
 * Parse and check the player's response stream.
 */
void Player::update_status()
{
	int response;
	char buf[512];
		
	while(fgets(buf, sizeof buf, resp)) {
		
		static const char *prs = "MAIEngine result:";
		
		if(!strncmp(prs, buf, strlen(prs)) &&
		   sscanf(buf + strlen(prs) + 1, "%x", &response) == 1) {

			switch(response) {
				case 0x00000008:
					last_err_msg = "opening file failed";
					break;
				case 0x00000025:
					last_err_msg = "unknown player command";
					break;
				case 0x00000020:
					last_err_msg = "invalid player command issued";
					break;
				case 0x00000028:
					last_err_msg = "file format not supported";
					break;
				case 0x00000021:
					last_err_msg = "shared video codec library not found";
					break;
				default:
					if(response)
						last_err_msg = buf;
					break;
			}
			
			if(response) {
				std::cerr << "ERROR: " << last_err_msg << std::endl;
				status = ERROR;
			}
		}

		*buf = '\0';
	}
}

void Player::open(Player::Codec codec, std::string path)
{
	tell("open " + cmd_codecs[codec] + " \"" + path  + "\"");
	initialized = true;
}

void Player::play()
{
	if(init_check()) return;

	if(status == PLAYING) {
		std::cerr << "invalid request: already playing" << std::endl; 
		return;
	}
	
	tell("play");
	status = PLAYING;
}


void Player::pause()
{
	if(init_check()) return;

	if(status == PAUSED) {
		std::cerr << "invalid request: already paused" << std::endl; 
		return;
	}
	
	tell("pause");
	status = PAUSED;
}

void Player::stop()
{
	if(init_check()) return;

	if(status == STOPPED) {
		std::cerr << "invalid request: already stopped" << std::endl; 
		return;
	}
	
	tell("pause");
	tell("seek 0:0");
	status = STOPPED;
}


